package com.kuaizu.es.utils;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.kuaizu.es.pojo.PageData;
import kuaizu.common.esindex.EsIndexConst;
import jakarta.annotation.PostConstruct;
import kuaizu.common.exception.MassageException;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xcontent.json.JsonXContent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author: wangmx15
 * @date: 2025/8/23
 **/
@Component
public class EsUtil {
    private static final Logger log = LoggerFactory.getLogger(EsUtil.class);
    @Autowired
    @Qualifier("restHighLevelClient")
    private RestHighLevelClient esClient;

    String PROJECT_INDEX = EsIndexConst.PROJECT_INDEX;

    @PostConstruct
    public void createProjectIndex() {
        // 1. 检查索引是否已存在
        boolean indexExists = false;
        try {
            indexExists = esClient.indices().exists(new GetIndexRequest(PROJECT_INDEX), RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new MassageException("索引获取失败");
        }
        if (indexExists) {
            System.out.println("索引 [" + PROJECT_INDEX + "] 已存在，无需重复创建");
            return;
        }

        // 2. 构建索引设置（分片/副本，根据数据量调整）
        CreateIndexRequest createReq = new CreateIndexRequest(PROJECT_INDEX);
        createReq.settings(Settings.builder()
                .put("number_of_shards", 3)    // 主分片：数据量<1000万时建议3-5个
                .put("number_of_replicas", 1)  // 副本：生产环境建议1个（高可用）
                .put("index.mapping.total_fields.limit", 200)  // 限制字段总数，避免滥用
        );

// 3. 构建映射（核心：适配精确筛选和分词查询）
        XContentBuilder mapping = null;
        try {
            mapping = JsonXContent.contentBuilder()
                    .startObject()
                    .startObject("properties")
                    // -------------------------- 1. 精确筛选字段（keyword类型）--------------------------
                    .startObject("school")  // 学校ID（如964）
                    .field("type", "keyword")  // 精确匹配，不分词
                    .field("doc_values", true)  // 支持聚合和排序（可选）
                    .endObject()
                    .startObject("majorClassId")  // 专业班级ID（新增字段，精确筛选）
                    .field("type", "keyword")
                    .field("doc_values", true)
                    .endObject()
                    .startObject("creatorOpenid")  // 冗余：创建者OpenID（如需精确筛选）
                    .field("type", "keyword")
                    .endObject()
                    .startObject("auditStatus")  // 审核状态（如0=待审核，精确筛选）
                    .field("type", "keyword")  // 用keyword而非integer，避免范围查询误触
                    .endObject()

                    // -------------------------- 2. 分词查询字段（text+IK分词）--------------------------
                    .startObject("projectName")  // 项目名称：全文检索
                    .field("type", "text")
                    .field("analyzer", "ik_max_word")  // 细粒度分词（如“智能分选”拆分为“智能”“分选”）
                    .field("search_analyzer", "ik_smart")  // 查询时分词更粗（提升效率）
                    .startObject("fields")  // 多字段：同时支持“分词查询”和“精确匹配”
                    .startObject("keyword")  // 如：精确匹配“面向工业固废...”
                    .field("type", "keyword")
                    .field("ignore_above", 256)  // 超过256字符不索引（避免长文本占用空间）
                    .endObject()
                    .endObject()
                    .endObject()
                    .startObject("projectInfo")  // 项目详情：全文检索
                    .field("type", "text")
                    .field("analyzer", "ik_max_word")
                    .field("search_analyzer", "ik_smart")
                    .endObject()
                    .startObject("skillDetails")  // 技能详情：全文检索
                    .field("type", "text")
                    .field("analyzer", "ik_max_word")
                    .field("search_analyzer", "ik_smart")
                    .endObject()

                    // -------------------------- 3. 其他基础字段（按需配置）--------------------------
                    .startObject("id")  // 项目ID（唯一标识）
                    .field("type", "long")
                    .endObject()
                    .startObject("createdAt")  // 创建时间（支持范围查询，如“近7天”）
                    .field("type", "date")
                    .field("format", "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis")
                    .endObject()
                    .startObject("lookcount")  // 浏览量（支持排序，如“热门项目”）
                    .field("type", "integer")
                    .endObject()
                    .startObject("emailPromotion")  // 是否邮件推广（布尔值）
                    .field("type", "boolean")
                    .endObject()
                    .endObject()
                    .endObject();
        } catch (IOException e) {
            throw new MassageException("索引初始化创建失败");
        }

        // 4. 绑定映射并执行创建
        createReq.mapping(mapping);
        CreateIndexResponse response = null;
        try {
            response = esClient.indices().create(createReq, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new MassageException("索引创建执行失败");
        }

        // 5. 验证结果
        if (response.isAcknowledged()) {
            System.out.println("索引 [" + PROJECT_INDEX + "] 创建成功");
        } else {
            throw new RuntimeException("索引 [" + PROJECT_INDEX + "] 创建失败，请检查ES连接");
        }
    }


    public <T> PageData<T> returnDatatShift(SearchResponse returnData,T obj) {
        PageData data = new PageData();
        log.info("返回值对象{}", returnData);
        //获取起总条数
        data.setTotal(Objects.requireNonNull(returnData.getHits().getTotalHits()).value);
        SearchHit[] searchHits =returnData.getHits().getHits();
        if(ObjectUtil.isNull(searchHits)){
            return null;
        }
        List<T> d = new ArrayList<>();
        for (SearchHit hit : searchHits) {
            // 获取文档源数据（JSON格式）
            String sourceAsString = hit.getSourceAsString();
            //将字符串转成Vo对象
            T o = (T) JSONUtil.toBean(sourceAsString, obj.getClass());
            d.add(o);
        }
        data.setData(d);
        return data;
    }
}
